home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / games / nhak_src.zip / SP_LEV.C < prev    next >
C/C++ Source or Header  |  1993-03-16  |  14KB  |  628 lines

  1. /*    SCCS Id: @(#)sp_lev.c    3.0    89/01/11
  2. /*    Copyright (c) 1989 by Jean-Christophe Collet */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * This file contains the various functions that are related to the special
  7.  * levels.
  8.  * It contains also the special level loader.
  9.  *
  10.  */
  11.  
  12. #include "hack.h"
  13.  
  14. #ifdef STRONGHOLD
  15. #include "sp_lev.h"
  16.  
  17. #if defined(MACOS) || (defined(MSDOS) && !defined(AMIGA))
  18. # define RDMODE "rb"
  19. #else
  20. # define RDMODE "r"
  21. #endif
  22.  
  23. #define LEFT    1
  24. #define CENTER    2
  25. #define RIGHT    3
  26. #define TOP    1
  27. #define BOTTOM    3
  28.  
  29. static walk NEARDATA walklist[50];
  30. extern int x_maze_max, y_maze_max;
  31.  
  32. #ifdef MACOS
  33. char **Map;
  34. #else
  35. static char Map[COLNO][ROWNO];
  36. #endif
  37. static char robjects[10], rloc_x[10], rloc_y[10], rmonst[10],
  38.     ralign[3] = { A_CHAOS, A_NEUTRAL, A_LAW };
  39. static xchar NEARDATA xstart, NEARDATA ystart, NEARDATA xsize, NEARDATA ysize;
  40.  
  41. static void FDECL(make_walls_nondiggable, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
  42. static int NDECL(rnddoor);
  43. static int NDECL(rndtrap);
  44. static void FDECL(get_location, (schar *,schar *));
  45. static void FDECL(shuffle, (char *,XCHAR_P));
  46. static void FDECL(shuffle2, (char *,char *,XCHAR_P));
  47. static boolean FDECL(load_rooms, (FILE *));
  48. static void FDECL(maze1xy, (coord *));
  49. static boolean FDECL(load_maze, (FILE *));
  50.  
  51. /*
  52.  * Make walls of the area (x1, y1, x2, y2) non diggable
  53.  */
  54.  
  55. static void
  56. make_walls_nondiggable(x1,y1,x2,y2)
  57. xchar x1, y1, x2, y2;
  58. {
  59.     register xchar x, y;
  60.  
  61.     for(y = y1; y <= y2; y++)
  62.         for(x = x1; x <= x2; x++)
  63.         if(IS_WALL(levl[x][y].typ))
  64.             levl[x][y].diggable |= W_NONDIGGABLE;
  65. }
  66.  
  67. /*
  68.  * Choose randomly the state (nodoor, open, closed or locked) for a door
  69.  */
  70.  
  71. static int
  72. rnddoor()
  73. {
  74.     int i;
  75.     
  76.     i = 1 << rn2(5);
  77.     i >>= 1;
  78.     return i;
  79. }
  80.  
  81. /* 
  82.  * Select a random trap
  83.  */
  84.  
  85. static int
  86. rndtrap()
  87. {
  88.     return(rnd(TRAPNUM-1));
  89. }
  90.  
  91. /* 
  92.  * Coordinates in special level files are handled specially:
  93.  *
  94.  *    if x or y is -11, we generate a random coordinate.
  95.  *    if x or y is between -1 and -10, we read one from the corresponding
  96.  *    register (x0, x1, ... x9).
  97.  *    if x or y is nonnegative, we convert it from relative to the local map
  98.  *    to global coordinates.
  99.  */
  100.  
  101. static void
  102. get_location(x, y)
  103. schar *x, *y;
  104. {
  105.     int cpt = 0;
  106.  
  107.     if (*x >= 0) {            /* normal locations */
  108.         *x += xstart;
  109.         *y += ystart;
  110.     } else if (*x > -11) {        /* special locations */
  111.         *y = ystart + rloc_y[ - *y - 1];
  112.         *x = xstart + rloc_x[ - *x - 1];
  113.     } else {            /* random location */
  114.         do {
  115.             *x = xstart + rn2((int)xsize);
  116.             *y = ystart + rn2((int)ysize);
  117.         } while (cpt < 100 &&
  118.              levl[*x][*y].typ != ROOM &&
  119.              levl[*x][*y].typ != CORR);
  120.         if(cpt >= 100)
  121.             panic("get_location: can't find a place!");
  122.     }
  123.  
  124.     if (*x < 0 || *x > x_maze_max || *y < 0 || *y > y_maze_max) {
  125.         impossible("get_location: (%d,%d) out of bounds", *x, *y);
  126.         *x = x_maze_max; *y = y_maze_max;
  127.     }
  128. }
  129.  
  130. /*
  131.  * Shuffle the registers for locations, objects or monsters
  132.  */
  133.  
  134. static void
  135. shuffle(list, n)
  136. char list[];
  137. xchar n;
  138. {
  139.     int i, j;
  140.     char k;
  141.  
  142.     for(i = n-1; i; i--) {
  143.         j = rn2(i);
  144.  
  145.         k = list[j];
  146.         list[j] = list[i];
  147.         list[i] = k;
  148.     }
  149. }
  150.  
  151. /* 
  152.  * Shuffle two arrays in the same order (for rloc_x & rloc_y)
  153.  */
  154.  
  155. static void
  156. shuffle2(list1, list2, n)
  157. char list1[], list2[];
  158. xchar n;
  159. {
  160.     int i, j;
  161.     char k1, k2;
  162.  
  163.     for(i = n-1; i; i--) {
  164.         j = rn2(i);
  165.  
  166.         k1 = list1[j];
  167.         k2 = list2[j];
  168.  
  169.         list1[j] = list1[i];
  170.         list2[j] = list2[i];
  171.  
  172.         list1[i] = k1;
  173.         list2[i] = k2;
  174.     }
  175. }
  176.  
  177. /* 
  178.  * NOT YET IMPLEMENTED!!!
  179.  */
  180.  
  181. static boolean
  182. load_rooms(fd)
  183. FILE *fd;
  184. {
  185.     return FALSE;
  186. }
  187.  
  188. /*
  189.  * Select a random coordinate in the maze.
  190.  *
  191.  * We want a place not 'touched' by the loader.  That is, a place in
  192.  * the maze outside every part of the special level.
  193.  */
  194.  
  195. static void
  196. maze1xy(m)
  197. coord *m;
  198. {
  199.     do {
  200.         m->x = rn1(x_maze_max - 3, 3);
  201.         m->y = rn1(y_maze_max - 3, 3);
  202.     } while (!(m->x % 2) || !(m->y % 2) || Map[m->x][m->y]);
  203. }
  204.  
  205. /* 
  206.  * The Big Thing: special maze loader
  207.  *
  208.  * Could be cleaner, but it works.
  209.  */
  210.  
  211. static boolean
  212. load_maze(fd)
  213. FILE *fd;
  214. {
  215.     xchar   x, y, n, typ;
  216.     char    c;
  217.  
  218.     xchar   numpart = 0, nwalk = 0;
  219.     uchar   halign, valign;
  220.  
  221.     int     xi, yi, dir;
  222.     coord   mm;
  223.     int     mapcount, mapcountmax, mapfact;
  224.  
  225.     region  tmpregion;
  226.     door    tmpdoor;
  227.     trap    tmptrap;
  228.     monster tmpmons;
  229.     object  tmpobj;
  230.     drawbridge tmpdb;
  231.     walk    tmpwalk;
  232.     digpos  tmpdig;
  233.     lad     tmplad;
  234. #ifdef ALTARS
  235.     altar   tmpaltar;
  236. #endif
  237.  
  238.     /* shuffle alignments */
  239.     shuffle(ralign,3);
  240.  
  241.     /* Initialize map */
  242.     xupstair = yupstair = xdnstair = ydnstair = doorindex = 0;
  243.     for(x = 2; x <= x_maze_max; x++)
  244.     for(y = 2; y <= y_maze_max; y++) {
  245. #ifndef WALLIFIED_MAZE
  246.         levl[x][y].typ = STONE;
  247. #else
  248.         levl[x][y].typ = ((x % 2) && (y % 2)) ? STONE : HWALL;
  249. #endif
  250.         Map[x][y] = 0;
  251.     }
  252.  
  253.     /* Start reading the file */
  254.     numpart = fgetc(fd); /* Number of parts */
  255.     if (!numpart || numpart > 9)
  256.     panic("load_maze error: numpart = %d", (int) numpart);
  257.  
  258.     while (numpart--) {
  259.     halign = fgetc(fd); /* Horizontal alignment */
  260.     valign = fgetc(fd); /* Vertical alignment */
  261.     xsize  = fgetc(fd); /* size in X */
  262.     ysize  = fgetc(fd); /* size in Y */
  263.  
  264.     switch((int) halign) {
  265.         case LEFT:        xstart = 3;                 break;
  266.         case CENTER:    xstart = 2+((x_maze_max-2-xsize)/2);    break;
  267.         case RIGHT:     xstart = x_maze_max-xsize-1;        break;
  268.     }
  269.     switch((int) valign) {
  270.         case TOP:        ystart = 3;                 break;
  271.         case CENTER:    ystart = 2+((y_maze_max-2-ysize)/2);    break;
  272.         case BOTTOM:    ystart = y_maze_max-ysize-1;        break;
  273.     }
  274.     if (!(xstart % 2)) xstart++;
  275.     if (!(ystart % 2)) ystart++;
  276.  
  277.     /* Load the map */
  278.     for(y = ystart; y < ystart+ysize; y++)
  279.         for(x = xstart; x < xstart+xsize; x++) {
  280.         levl[x][y].typ = fgetc(fd);
  281.         initsym(x,y);
  282.         /* secret doors default closed */
  283.         if (levl[x][y].typ == SDOOR)
  284.           levl[x][y].doormask = D_CLOSED;
  285.         Map[x][y] = 1;
  286.         }
  287.  
  288.     n = fgetc(fd); /* Random objects */
  289.     if(n) {
  290.         (void) fread((genericptr_t)robjects, 1, (int) n, fd);
  291.         shuffle(robjects, n);
  292.     }
  293.  
  294.     n = fgetc(fd); /* Random locations */
  295.     if(n) {
  296.         (void) fread((genericptr_t)rloc_x, 1, (int) n, fd);
  297.         (void) fread((genericptr_t)rloc_y, 1, (int) n, fd);
  298.         shuffle2(rloc_x, rloc_y, n);
  299.     }
  300.  
  301.     n = fgetc(fd); /* Random monsters */
  302.     if(n) {
  303.         (void) fread((genericptr_t)rmonst, 1, (int) n, fd);
  304.         shuffle(rmonst, n);
  305.     }
  306.  
  307.     n = fgetc(fd); /* Number of subrooms */
  308.     while(n--) {
  309.         (void) fread((genericptr_t)&tmpregion, sizeof(tmpregion), 1, fd);
  310.         if (nroom >= MAXNROFROOMS) continue;
  311.  
  312.         get_location(&tmpregion.x1, &tmpregion.y1);
  313.         get_location(&tmpregion.x2, &tmpregion.y2);
  314.  
  315.         rooms[nroom].lx = tmpregion.x1;
  316.         rooms[nroom].ly = tmpregion.y1;
  317.         rooms[nroom].hx = tmpregion.x2;
  318.         rooms[nroom].hy = tmpregion.y2;
  319.         rooms[nroom].rtype = tmpregion.rtype;
  320.         rooms[nroom].rlit = tmpregion.rlit;
  321.         if (tmpregion.rlit == 1)
  322.             for(x = rooms[nroom].lx-1; x <= rooms[nroom].hx+1; x++)
  323.                 for(y = rooms[nroom].ly-1; y <= rooms[nroom].hy+1; y++)
  324.                     levl[x][y].lit = 1;
  325.  
  326.         rooms[nroom].fdoor = rooms[nroom].doorct = 0;
  327.  
  328.         ++nroom;
  329.         rooms[nroom].hx = -1;
  330.     }
  331.  
  332.     n = fgetc(fd); /* Number of doors */
  333.     while(n--) {
  334.         struct mkroom *croom = &rooms[0], *broom;
  335.         int tmp;
  336.  
  337.         (void) fread((genericptr_t)&tmpdoor, sizeof(tmpdoor), 1, fd);
  338.  
  339.         x = tmpdoor.x;    y = tmpdoor.y;
  340.         typ = tmpdoor.mask == -1 ? rnddoor() : tmpdoor.mask;
  341.  
  342.         get_location(&x, &y);
  343.         levl[x][y].doormask = typ;
  344.         mnewsym(x,y);
  345.  
  346.         /* Now the complicated part, list it with each subroom */
  347.         /* The dog move and mail daemon routines use this */
  348.         while(croom->hx >= 0 && doorindex < DOORMAX) {
  349.             if(croom->hx >= x-1 && croom->lx <= x+1 &&
  350.                croom->hy >= y-1 && croom->ly <= y+1) {
  351.             /* Found it */
  352.             croom->doorct++;
  353.  
  354.             /* Append or insert into doors[] */
  355.             broom = croom+1;
  356.             if(broom->hx < 0) tmp = doorindex;
  357.             else
  358.                 for(tmp = doorindex; tmp > broom->fdoor; tmp--)
  359.                 doors[tmp] = doors[tmp-1];
  360.  
  361.             doors[tmp].x = x;
  362.             doors[tmp].y = y;
  363.             doorindex++;
  364.  
  365.             for( ; broom->hx >= 0; broom++) broom->fdoor++;
  366.             }
  367.             croom++;
  368.         }
  369.     }
  370.  
  371.     n = fgetc(fd); /* Number of traps */
  372.     while(n--) {
  373.         (void) fread((genericptr_t)&tmptrap, sizeof(tmptrap), 1, fd);
  374.  
  375.         x = tmptrap.x;    y = tmptrap.y;
  376.         typ = (tmptrap.type == -1 ? rndtrap() : tmptrap.type);
  377.  
  378.         get_location(&x, &y);
  379.         (void) maketrap(x, y, typ);
  380.     }
  381.  
  382.     n = fgetc(fd);    /* Number of monsters */
  383.     while(n--) {
  384.         (void) fread((genericptr_t)&tmpmons, sizeof(tmpmons), 1, fd);
  385.  
  386.         x = tmpmons.x;    y = tmpmons.y;
  387.         get_location(&x, &y);
  388.  
  389.         if    (tmpmons.class >= 0)
  390.             c = tmpmons.class;
  391.         else if (tmpmons.class > -11)
  392.             c = rmonst[-tmpmons.class - 1];
  393.         else
  394.             c = 0;
  395.  
  396.         if (!c)
  397.             (void) makemon((struct permonst *) 0, x, y);
  398.         else if (tmpmons.id != -1)
  399.             (void) makemon(&mons[tmpmons.id], x, y);
  400.         else
  401.             (void) makemon(mkclass(c), x, y);
  402.     }
  403.  
  404.     n = fgetc(fd); /* Number of objects */
  405.     while(n--) {
  406.         (void) fread((genericptr_t) &tmpobj, sizeof(object),1, fd);
  407.  
  408.         x = tmpobj.x;  y = tmpobj.y;
  409.         get_location(&x, &y);
  410.  
  411.         if    (tmpobj.class >= 0)
  412.             c = tmpobj.class;
  413.         else if (tmpobj.class > -11)
  414.             c = robjects[-tmpobj.class - 1];
  415.         else
  416.             c = 0;
  417.  
  418.         if (!c)
  419.             (void) mkobj_at(0, x, y, TRUE);
  420.         else if (tmpobj.id != -1)
  421.             (void) mksobj_at(tmpobj.id, x, y);
  422.         else
  423.             (void) mkobj_at(c, x, y, TRUE);
  424.     }
  425.  
  426.     n = fgetc(fd); /* Number of drawbridges */
  427.     while(n--) {
  428.         (void) fread((genericptr_t)&tmpdb, sizeof(tmpdb), 1, fd);
  429.  
  430.         x = tmpdb.x;  y = tmpdb.y;
  431.         get_location(&x, &y);
  432.  
  433.         if (!create_drawbridge(x, y, tmpdb.dir, tmpdb.open))
  434.             impossible("Cannot create drawbridge.");
  435.     }
  436.  
  437.     n = fgetc(fd); /* Number of mazewalks */
  438.     while(n--) {
  439.         (void) fread((genericptr_t)&tmpwalk, sizeof(tmpwalk), 1, fd);
  440.  
  441.         get_location(&tmpwalk.x, &tmpwalk.y);
  442.  
  443.         walklist[nwalk++] = tmpwalk;
  444.     }
  445.  
  446.     n = fgetc(fd); /* Number of non_diggables */
  447.     while(n--) {
  448.         (void) fread((genericptr_t)&tmpdig, sizeof(tmpdig), 1, fd);
  449.  
  450.         get_location(&tmpdig.x1, &tmpdig.y1);
  451.         get_location(&tmpdig.x2, &tmpdig.y2);
  452.  
  453.         make_walls_nondiggable(tmpdig.x1, tmpdig.y1,
  454.                        tmpdig.x2, tmpdig.y2);
  455.     }
  456.  
  457.     n = fgetc(fd); /* Number of ladders */
  458.     while(n--) {
  459.         (void) fread((genericptr_t)&tmplad, sizeof(tmplad), 1, fd);
  460.  
  461.         x = tmplad.x;  y = tmplad.y;
  462.         get_location(&x, &y);
  463.  
  464.         levl[x][y].typ = LADDER;
  465.         if (tmplad.up == 1) {
  466.             xupladder = x;    yupladder = y;
  467.             levl[x][y].ladder = LA_UP;
  468.         } else {
  469.             xdnladder = x;    ydnladder = y;
  470.             levl[x][y].ladder = LA_DOWN;
  471.         }
  472.     }
  473.  
  474. #ifdef ALTARS
  475.     n = fgetc(fd); /* Number of altars */
  476.     while(n--) {
  477.         (void) fread((genericptr_t)&tmpaltar, sizeof(tmpaltar), 1, fd);
  478.  
  479.         x = tmpaltar.x;  y = tmpaltar.y;
  480.         get_location(&x, &y);
  481.  
  482.         typ = tmpaltar.align == -11 ? rn2(3) :
  483.               (tmpaltar.align < 0    ? ralign[-tmpaltar.align-1] :
  484.                           tmpaltar.align);
  485.         if (tmpaltar.shrine)
  486.             typ |= A_SHRINE;
  487.  
  488.         levl[x][y].typ = ALTAR;
  489.         levl[x][y].altarmask = typ;
  490.     }
  491. #endif /* ALTARS /**/
  492.     }
  493.  
  494.     while(nwalk--) {
  495.         xi = walklist[nwalk].x;
  496.         yi = walklist[nwalk].y;
  497.         dir = walklist[nwalk].dir;
  498.  
  499.         move(&xi, &yi, dir);
  500.         x = xi;
  501.         y = yi;
  502.  
  503. #ifndef WALLIFIED_MAZE
  504.         levl[x][y].typ = CORR;
  505. #else
  506.         levl[x][y].typ = ROOM;
  507. #endif
  508.  
  509.         /*
  510.          * We must be sure that the parity of the coordinates for
  511.          * walkfrom() is odd.  But we must also take into account
  512.          * what direction was chosen.
  513.          */
  514.         if(!(x % 2))
  515.         if (dir == W_EAST)
  516.             x++;
  517.         else
  518.             x--;
  519.  
  520. #ifndef WALLIFIED_MAZE
  521.         levl[x][y].typ = CORR;
  522. #else
  523.         levl[x][y].typ = ROOM;
  524. #endif
  525.  
  526.         if (!(y % 2))
  527.         if (dir == W_SOUTH)
  528.             y++;
  529.         else
  530.             y--;
  531.  
  532.         walkfrom(x, y);
  533.     }
  534.     wallification(2, 2, x_maze_max, y_maze_max, TRUE);
  535.  
  536.     /*
  537.      * If there's a significant portion of maze unused by the special level,
  538.      * we don't want it empty.
  539.      *
  540.      * Makes the number of traps, monsters, etc. proportional
  541.      * to the size of the maze.
  542.      */
  543.     mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2);
  544.  
  545.     for(x = 2; x < x_maze_max; x++)
  546.     for(y = 2; y < y_maze_max; y++)
  547.         if(Map[x][y]) mapcount--;
  548.  
  549.     if (mapcount > (int) (mapcountmax / 10)) {
  550.         mapfact = (int) ((mapcount * 100L) / mapcountmax);
  551.         for(x = rnd((int) (20 * mapfact) / 100); x; x--) {
  552.             maze1xy(&mm);
  553.             (void) mkobj_at(rn2(2) ? GEM_SYM : 0, mm.x, mm.y, TRUE);
  554.         }
  555.         for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
  556.             maze1xy(&mm);
  557.             (void) mksobj_at(BOULDER, mm.x, mm.y);
  558.         }
  559.         maze1xy(&mm);
  560.         (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y);
  561.         for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
  562.             maze1xy(&mm);
  563.             (void) makemon((struct permonst *) 0, mm.x, mm.y);
  564.         }
  565.         for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
  566.             maze1xy(&mm);
  567.             mkgold(0L,mm.x,mm.y);
  568.         }
  569.         for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
  570.             maze1xy(&mm);
  571.             (void) maketrap(mm.x, mm.y,rndtrap());
  572.         }
  573.     }
  574.     return TRUE;
  575. }
  576.  
  577. /*
  578.  * General loader
  579.  */
  580.  
  581. boolean
  582. load_special(name)
  583. const char *name;
  584. {
  585.     FILE *fd;
  586.     boolean result;
  587.     schar c;
  588.  
  589. #ifdef OS2_CODEVIEW
  590.     {
  591.     char tmp[PATHLEN];
  592.  
  593.     Strcpy(tmp,hackdir);
  594.     append_slash(tmp);
  595.     Strcat(tmp,name);
  596.     fd = fopen(tmp, RDMODE);
  597. #else
  598.     fd = fopen(name, RDMODE);
  599. # ifdef MACOS
  600.     if (!fd)
  601.         fd = openFile(name, RDMODE);
  602. # endif
  603. #endif
  604. #ifdef OS2_CODEVIEW
  605.     }
  606. #endif
  607.     if (!fd) return FALSE;
  608.  
  609.     if ((c = fgetc(fd)) == EOF) {
  610.         (void)fclose(fd);
  611.         return FALSE;
  612.     }
  613.  
  614.     switch (c) {
  615.         case 1:     /* Alas, this is not yet implemented. */
  616.             result = load_rooms(fd);
  617.             break;
  618.         case 2:     /* But this is implemented :-) */
  619.             result = load_maze(fd);
  620.             break;
  621.         default:    /* ??? */
  622.             result = FALSE;
  623.     }
  624.     (void)fclose(fd);
  625.     return result;
  626. }
  627. #endif /* STRONGHOLD /**/
  628.